/*
    The NeonX Library

    Copyright (c) 2013 darkcat

    Code covered by the MIT License
*/

#pragma once

// nx...
#include "config/general.h"
// nx_no_qualifier, nx_no_reference
#include "type/typedetect.h"
// nx::swap
#include "algorithm/algorithm.h"

//////////////////////////////////////////////////////////////////////////
NX_BEG
//////////////////////////////////////////////////////////////////////////

template <typename T>
class refer
{
public:
    typedef typename nx_no_qualifier(
            typename nx_no_reference(T)) type_t;
    typedef typename nx_no_reference(T)* value_t;

protected:
    value_t value_;

public:
    refer(type_t& r) : value_(&r) {}

    type_t&       operator* (void)       { return *value_; }
    const type_t& operator* (void) const { return *value_; }
    value_t       operator->(void)       { return value_; }
    const type_t* operator->(void) const { return value_; }

    refer& operator=(type_t& r)
    {
        value_ = &r;
        return (*this);
    }

    template <typename U>
    refer& operator=(refer<U>& r)
    {
        *value_ = *(r.value_);
        return (*this);
    }

    template <typename U>
    refer& swap(refer<U>& rhs)
    {
        nx::swap(*value_, *(rhs.value_));
        return (*this);
    }
};

/*
    Special swap algorithm
*/

template <typename T, typename U>
void swap(refer<T>& x, refer<U>& y)
{
    x.swap(y);
}

/*
    For get a reference of a variable
*/

template <typename T>
inline refer<T>       ref(T& r)          { return refer<T>(r); }
template <typename T>
inline refer<const T> ref(const T& r)    { return refer<const T>(r); }
template <typename T>
inline refer<T>&      ref(refer<T>& r)   { return r; }

template <typename T>
inline T&             unref(T& r)        { return r; }
template <typename T>
inline const T&       unref(const T& r)  { return r; }
template <typename T>
inline T&             unref(refer<T>& r) { return (*r); }

//////////////////////////////////////////////////////////////////////////
NX_END
//////////////////////////////////////////////////////////////////////////
